package cn.seaboot.admin.mybatis;

import cn.seaboot.admin.mvc.mask.Desensitize;
import cn.seaboot.admin.mvc.mask.ReturnValueDesensitization;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.Properties;

/**
 * 数据脱敏
 * <p>
 * 从根本上脱敏所有数据，mybatis查询返回数据之后立即脱敏，
 * 一般不需要做到这种程度，这会导致系统内部处理业务时，使用的数据也是脱敏的状态。
 *
 * @author Mr.css
 * @version 2023-06-28 15:53
 */
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
})
public class DesensitizationInterceptor implements Interceptor {

    private final ReturnValueDesensitization returnValueDesensitization;

    public DesensitizationInterceptor(ReturnValueDesensitization returnValueDesensitization) {
        this.returnValueDesensitization = returnValueDesensitization;
    }

    /**
     * 在拦截目标对象的方法时，实际执行的增强逻辑，我们一般在该方法中实现自定义逻辑
     *
     * @param invocation -
     * @return 执行结果
     * @throws Throwable -
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Desensitize desensitize = invocation.getMethod().getAnnotation(Desensitize.class);
        if (desensitize == null) {
            // ignore
            return invocation.proceed();
        } else {
            // desensitize data
            Object ret = invocation.proceed();
            returnValueDesensitization.process(ret);
            return ret;
        }
    }

    /**
     * 生成代理类
     * <p>
     * 用于返回原生目标对象或它的代理对象，当返回的是代理对象的时候，会调用 intercept 方法
     *
     * @param target 被代理的类，一般是 mybatis 默认的四大拦截
     * @return this
     */
    @Override
    public Object plugin(Object target) {
        if (target instanceof DefaultResultSetHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }


    /**
     * 可以用于读取配置文件中通过property标签配置的一些属性，设置一些属性变量
     *
     * @param properties 环境参数
     */
    @Override
    public void setProperties(Properties properties) {
        // do nothing
    }
}
